#pragma once

/*
 * connection manager.
 */

#include "type.h"
#include <functional>
#include "connection_map.h"
#include "asio/asio.hpp"


namespace KCP {
	class CConnectionMgr : asio::noncopyable {
	public:
		// server connection mgr
		CConnectionMgr(asio::io_service& ioService, const std::string& ip, uint16 port);
		CConnectionMgr(asio::io_service& ioService);
		virtual ~CConnectionMgr();
		typedef std::function<event_callback_t> callback_func;
		enum eMode {
			// server mode.
			mode_server = 0,
			// client mode
			mode_client,
		};

	public:
		void         update();
		void         set_callback(const std::function<event_callback_t>& func);
		int          event_callback_func(CConnection* conn, eEventType eventType, const char* msg, int len);

		void         stop();
		void         disconnect(CConnection* conn, const std::string& msg);

		// async send udp data.
		void         send_udp(const char* msg, int len, const udp::endpoint& endpoint);

		// find connection.
		CConnection* find(uint32 conv);

		// server or client mode
		void         setMode(eMode mode) { m_mode = mode; }
		eMode        getMode() { return m_mode; }

		// send establish pack
		void         sendEstablishPack(uint32 convId, const udp::endpoint& endPoint);
		size_t       allConnectionSize() const { return this->m_connections.AllCount(); }

	public:
		// kcp disconnection
		void     handleKCPDisconnect(CConnection* conn, const std::string& msg);

		// kcp recv data
		int      handleKCPData(CConnection* conn, const char* msg, int len);

		// kcp connection
		void     handleKCPConnect(CConnection* conn, const char* msg, int len);

	private:
		// async recv request.
		void     startAsyncRecv();

		// handle udp connection.
		void     handleConnectPack(const std::string& data, const udp::endpoint& endPoint);

		// handle udp data packet.
		bool     handleDataPack(const std::string& data, const udp::endpoint& endPoint);

		// check connection packet.
		bool     checkConnectPack(const std::string& data);

	private:
		// server or client mode
		eMode            m_mode;

		callback_func    m_eventCallback;

		// udp socket
		udp::socket      m_udpSocket;

		// !!remote address
		udp::endpoint    m_endPoint;

		// connect list.
		CConnectionMap   m_connections;

		// udp recv buff
		char             m_recvBuff[KCP_PACKET_MAX_SIZE];
	};
}